/* ***** BEGIN LICENSE BLOCK *****
 *   Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is JsWs.
 *
 * The Initial Developer of the Original Code is
 * Chris Winberry.
 * Portions created by the Initial Developer are Copyright (C) 2007
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 * 
 * ***** END LICENSE BLOCK ***** */

/*** FILES & LOCATIONS ***/
var JSWS_ROOT				= "/jsws";					// Root folder for all JsWs files
var JSWS_DOCROOT			= "/htdocs";	// Folder that contains all served content
var JSWS_DB_ROOT			= "/data";		// Folder where SQLite/MozStorage DB files are kept
var JSWS_SCRIPT_FILEEXT		= "jss";					// File extension for scripts that JsWs will execute
var JSWS_DB_FILEEXT			= "storage";				// File extension for SQLite/MozStorage DB files

/*** PREFERENCES ***/
var JSWS_PREF_ROOT			= "extensions.jsws.";			// Root of all preference settings
var JSWS_PREF_AUTOSTART		= JSWS_PREF_ROOT + "autostart";	// Flag - should JsWs start automatically
var JSWS_PREF_PORT			= JSWS_PREF_ROOT + "port";		// TCP port JsWs will listen on
var JSWS_PREF_LOCALONLY		= JSWS_PREF_ROOT + "localOnly";	// Flag - should JsWs only accept loopback connections
var JSWS_PREF_THREADED		= JSWS_PREF_ROOT + "threaded";	// Flag - should JsWs run in a separate thread

/*** MODULES ***/
var JSWS_PREF_MODULES_ROOT		= JSWS_PREF_ROOT + "modules.";	// Root of all module registrations
var JSWS_MODULES_ROOTKEY		= "root";						// Reserved module name for "/"
var JSWS_MODULES_IDKEY			= "id";							// Key for modules' extension ID
var JSWS_MODULES_NAMEKEY		= "name";						// Key for modules' display name
var JSWS_MODULES_EXTENSIONPATHKEY	= "extPath";				// Key for modules' root folder
var JSWS_MODULES_CONTENTPATHKEY	= "contentPath";				// Key for modules' location of servable content
var JSWS_MODULES_VIRTUALPATHKEY	= "virtualPath";				// Key for modules' mapping to a JsWs path
var JSWS_MODULES_STARTPAGEKEY	= "startPage";					// Key for modules' default start page
var JSWS_MODULES_HANDLERKEY		= "handler";					// Key for modules' page handler
var JSWS_MODULES_INITPAGEKEY	= "initPage";					// Key for modules' initialization page
var JSWS_MODULES_DESCRIPTIONKEY	= "description";				// Key for modules' description

if (!Cc)
	var Cc = Components.classes;
if (!Ccon)
	var Ccon = Components.Constructor;
if (!Ci)
	var Ci = Components.interfaces;

var nsLocalFile = Ccon("@mozilla.org/file/local;1", "nsILocalFile", "initWithPath");


/**
 * Makes one "class" inherit from another while maintaining constructor chain
 * and not breaking instanceof usage
 * @param {Class} base constructor to inherited from
 * @param {Class} sub constructor to subclass from base
 */
function SubClass (base, sub) {
	function proxyObject () { }
	proxyObject.prototype = base.prototype;

	var proxy = new proxyObject();
	proxy.constructor = sub;
	sub.baseConstructor = base;
	sub.prototype = proxy;
}

/**
 * Base class for exceptions to inherit from
 * @class This class forms the basis for all other exceptions. It provides
 *  consistent display formatting and wrapping of earlier/inner exceptions.
 *  Inner exceptions are a convenient way to establish a lazy call stack for
 *  debugging and error reporting.
 * @constructor
 * @param {String} msg Description of exception
 * @param {Number} code (optional) Error code
 * @param {Exception} ex (optional) An earlier exception to wrap
 * @param {Arguments} args (optional) Arguments array of a functions
 */
function ExBase (msg, code, ex, args) {
	/**
	 * Description of the exception
	 * @type String
	 */
	this.message = "";
	/**
	 * Exception error code
	 * @type Number
	 */
	this.code = 0;
	/**
	 * Earlier exception wrapped by the current exception
	 * @type Exception
	 */
	this.originalEx = null;
	/**
	 * Arguments passed to code throwing the exception
	 * @type Arguments
	 */
	this.args = null;

	this.init(msg, code, ex, args);
}


/** @private */
ExBase.prototype.init = function (msg, code, ex, args) {
	if (code != null)
		this.code = code;
	this.message = msg;
	if (ex != null)
		this.originalEx = ex;
	if (args != null)
		this.args = args;
}


/**
 * @returns Name of the exception type
 * @type String
 */
ExBase.prototype.name = function () {
	return /(\w+)\(/.exec(this.constructor.toString())[1];
}


/**
 * Serializer
 * @type String
 */
ExBase.prototype.toString = function () {
	return("{{" + this.name() + "}}"
		+ " [ErrNum: " + this.code + "] :"
		+ " " + this.message
		+ ((this.args != null) ? this.formatArgs(this.args) : "")
		+ ((this.originalEx != null) ? "\n" + 
			((this.originalEx instanceof ExBase) ? this.originalEx : this.formatExternalEx(this.originalEx))
			:
			"")
		);
}


/** @private */
ExBase.prototype.formatArgs = function (args) {
	var matches = args.callee.toString().match(/^\s*function\s+([^\(\)]+)\s*\(([^\(\)]*)\) \{/i);
	var funcName = matches[1];
	var params = matches[2].split(/,\s*/);
	
	var output = "\n(Function:\n";
	output += "  " + funcName + " (" + params.join(', ') + ")\n";
	output += "    # of args: " + args.length + "\n";
	for (var i = 0; i < args.length; i++) {
		output += "    " + (params[i] ? params[i] : "???") + ": (" + typeof args[i] + ") " + args[i] + "\n";
	}
	output += ")\n";
		
	return(output);
}


/** @private */
ExBase.prototype.formatExternalEx = function (ex) {
	return(
		"{{" + ex.name + "}}\n"
		+ "   Msg: " + ex.message + "\n"
		+ "   File: " + ex.fileName + "(Line:" + ex.lineNumber + ")\n"
		+ "   Stack: " + ex.stack
		);
}

/**
 * @class Exception class for parameter errors
 * @constructor
 * @base ExBase
 * @param {String} msg Description of exception
 * @param {Number} code (optional) Error code
 * @param {Exception} ex (optional) An earlier exception to wrap
 * @param {Arguments} args (optional) Arguments array of a functions
 */
function ExParamError (msg, code, ex, args) { ExParamError.baseConstructor.call(this, msg, code, ex, args); }
SubClass(ExBase, ExParamError);

